Add array-shape return type for localeconv() and shape-based localtime() return type extension - #6031
Merged
VincentLanglet merged 4 commits intoJul 10, 2026
Conversation
…time()` return type extension - Replace the bare `array` return type of `localeconv()` in `resources/functionMap.php` with the full array shape (string keys such as `decimal_point`/`thousands_sep`, int keys such as `frac_digits`, and `grouping: list<int>`), so accessing individual entries yields `string`/`int`/`list<int>` instead of `mixed`. - Add `LocaltimeFunctionDynamicReturnTypeExtension` for the sibling `localtime()` function, whose shape depends on the `associative_array` argument: a 9-element `list<int>` by default, the `tm_*` associative shape when the argument is `true`, and the union of both when the argument is an unknown bool.
staabm
reviewed
Jul 10, 2026
Express the documented value ranges (e.g. tm_sec 0-59, tm_hour 0-23) as int<min, max> instead of a plain int for both the list and associative localtime() return shapes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
staabm
approved these changes
Jul 10, 2026
staabm
reviewed
Jul 10, 2026
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
VincentLanglet
approved these changes
Jul 10, 2026
staabm
approved these changes
Jul 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
localeconv()was typed as returning a barearray, so reading individual entries (e.g.localeconv()['thousands_sep']) producedmixed. This caused false positives such as "should return string but returns mixed" and "Cannot cast mixed to string". The function actually returns a well-defined array shape, so we now express that shape.Changes
resources/functionMap.php: replaced'localeconv' => ['array']with the full array shape:array{decimal_point: string, thousands_sep: string, int_curr_symbol: string, currency_symbol: string, mon_decimal_point: string, mon_thousands_sep: string, positive_sign: string, negative_sign: string, int_frac_digits: int, frac_digits: int, p_cs_precedes: int, p_sep_by_space: int, n_cs_precedes: int, n_sep_by_space: int, p_sign_posn: int, n_sign_posn: int, grouping: list<int>}.src/Type/Php/LocaltimeFunctionDynamicReturnTypeExtension.phpfor the analogouslocaltime()function. Its return shape is conditional on the second (associative_array) argument, which a staticfunctionMapentry cannot express:falseargument →array{int, int, int, int, int, int, int, int, int}(a 9-element list)trueargument →array{tm_sec: int, tm_min: int, tm_hour: int, tm_mday: int, tm_mon: int, tm_year: int, tm_wday: int, tm_yday: int, tm_isdst: int}vendor/attributes.phpso the new#[AutowiredService]extension is registered.tests/PHPStan/Analyser/nsrt/localeconv.phpcovering both functions.Root cause
Several built-in PHP functions that return a fixed associative array were mapped to a bare
arrayinfunctionMap.php, losing all per-key type information. The pattern is "array-returning builtin typed as plainarray".localeconv()is fixed directly in the function map. Its immediate siblinglocaltime()(the next entry in the map, same locale/time family) had the same problem but its shape depends on an argument, so it needed a dynamic return type extension rather than a static shape.Test
tests/PHPStan/Analyser/nsrt/localeconv.phpasserts:localeconv()shape, plus that['thousands_sep']/['decimal_point']arestring,['frac_digits']isint, and['grouping']islist<int>(previouslymixed).localtime()list shape for the default/falseargument, the associativetm_*shape fortrue, and the union of both for an unknown bool argument.Confirmed the
localeconvassertions fail (mixed) before thefunctionMapchange and pass after.Fixes phpstan/phpstan#14949